"""
证件照正则化
"""
import re
import json
from handle.template import TemplateParser
from handle.parse_config import *
from common.time_convertor import TimeConverter
from common.stringUtils import hump2under_line, ExactCandidateFields
import copy

TC = TimeConverter()


class ParseOfDocuments(TemplateParser):
    def __init__(self, **kwargs):
        super(ParseOfDocuments, self).__init__(**kwargs)
        self._output_fields = self.requiredFields + self.optionalFields
        self._regular_fields = self.requiredFields + self.optionalFields + self._ownFields
        self._regular_map = self.__custom_regular_field_mapping()
        self.SINGLE = 1
        self.MULTI = 2
        self._line2mode = self.__field_key2mode()
        self._result = self.__init_result()
        self.ecf = ExactCandidateFields(self._regular_map)

    def __init_result(self):
        init_dict = {
            "originalData": "\n".join([item.text for item in self._sorted_ocr_result]),  # 原始数据
            "subCertificateName": self._subCertificateName,
            "certificateName": self._certificateName,
            "certificateType": self._certificateType,
        }
        for key in self._output_fields:
            init_dict[key] = ""
        return init_dict

    def __custom_regular_field_mapping(self):
        common_field = copy.deepcopy(COMMON_FIELDS)
        if self._certificateName == LICENSE:
            common_field["certificateCode"] = "^(统一社会?信用代码|社会信用代码|组织机构?代码)(.*)"
        elif self._certificateName == YLQXSCBAPZ:
            common_field["certificateCode"] = "^(备案号|备案编号)(.*)"
        elif self._certificateName == YPZCZ:
            common_field["supplierName"] = "(.{1,20}公司)"
            common_field["certificateCode"] = "^(批.{0,2}号)(.*)"
            common_field["certificateValidity"] = "^(有效期至|注册证有效.{0,2}至|至.{0,5}}年.{0,5}}月)(.*)"
            common_field["productValidity"] = "^药品(有效期|至.{0,5}}年.{0,5}}月)(.*)"
        elif self._certificateName == YLQXZCZ:
            common_field["certificateCode"] = "^(注册证.{0,1}号|编号:|注册号)(.*)"
        elif self._certificateName == YLQXBAZ:
            common_field["supplierName"] = "(.{1,20}公司)"
            common_field["certificateCode"] = "^([绵证]号|.{0,3}编号|号:)(.*)"
        return common_field

    def __field_key2mode(self):
        mode_dict = dict()
        for field_key in self._regular_fields:
            if field_key in ["businessScope", "structComposition"]:
                mode_dict[field_key] = self.MULTI
                continue
            mode_dict[field_key] = self.SINGLE
        return mode_dict

    def __get_date_from_text(self):
        for index in range(self._len_rect-1, -1, -1):
            if index in self.usedIds:
                continue
            if len(self._sorted_ocr_result[index].text) >= 15:
                continue
            valid_date = TC.convert_date(self._sorted_ocr_result[index].text)
            if not valid_date:
                continue
            self.usedIds.append(index)
            return valid_date
        return ""

    def __compare_date(self):
        issue_date = self._result.get("issueDate", "")
        validity = self._result.get("certificateValidity", "")
        try:
            if int(issue_date[0:4]) > int(validity[0:4]):
                self._result["issueDate"] = validity
                self._result["certificateValidity"] = issue_date
        except ValueError:
            return

    def _plot_rect(self, image_name="src.jpg"):
        import cv2 as cv
        import numpy as np
        image = np.asarray(self._image)
        for i in range(self._len_rect):
            single_line = self._sorted_ocr_result[i]
            bbox = single_line.srcBbox
            cv.line(image, (bbox[0], bbox[1]), (bbox[2], bbox[3]), (255, 0, 0), 1)
            cv.putText(image, str(i), (bbox[0], bbox[1]), cv.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 255), 1)
            cv.line(image, (bbox[2], bbox[3]), (bbox[4], bbox[5]), (255, 0, 0), 1)
            cv.line(image, (bbox[4], bbox[5]), (bbox[6], bbox[7]), (255, 0, 0), 1)
            cv.line(image, (bbox[6], bbox[7]), (bbox[0], bbox[1]), (255, 0, 0), 1)

        image = cv.cvtColor(image, cv.COLOR_RGB2BGR)
        cv.imwrite(image_name, image)

    def _issue_date_normalize(self, title2text):
        issue_date = TC.convert_date(title2text.get("issueDate", ""))
        create_date = TC.convert_date(title2text.get("createDate", ""))
        validity_date_lst = TC.convert_date(title2text.get("certificateValidity", "").split("至")[0])
        if not issue_date and not create_date:
            if len(validity_date_lst) == 2 and validity_date_lst[0]:
                return validity_date_lst[0]
            issue_date = self.__get_date_from_text()
            return issue_date

        elif issue_date:
            return issue_date
        else:
            return create_date

    @staticmethod
    def _legal_representative_normalize(title2text):
        representative = title2text.get("legalRepresentative", "")
        pattern = re.compile("\\w", re.A)
        representative = pattern.sub("", representative)
        return representative

    def _certificate_validity_normalize(self, title2text):
        validity = TC.convert_validity_date(title2text.get("certificateValidity", ""))
        if validity:
            return validity
        find_validity = self.__get_date_from_text()
        if not find_validity:
            return "9999-12-31"
        return find_validity

    @staticmethod
    def _normalize_company_name(title2text):
        company_name = title2text.get("supplierName", "")
        if not company_name:
            company_name = title2text.get("registerRepresentative", "")
        if not company_name:
            company_name = title2text.get("manufacturer", "")
        return company_name

    @staticmethod
    def _common_normalize(field, title2text):
        field_val = title2text.get(field, "")
        return field_val

    def _normalize_every_field(self, title2text):
        for field in self._output_fields:
            attr = hump2under_line("_" + field.split("_")[0] + "_normalize")
            if field in ["supplierName", "registerRepresentative", "manufacturer"]:
                normalized_val = self._normalize_company_name(title2text)
            elif hasattr(self, attr):
                normalized_val = self.__getattribute__(attr)(title2text)
            else:
                normalized_val = self._common_normalize(field, title2text)
            normalized_val = self.left_strip(normalized_val)
            self._result[field] = normalized_val
        self.__compare_date()

    def get_center2id_position(self):
        """获取中心位置Index"""
        title2id = dict()
        for field_key in self._regular_fields:
            center_id = -1
            for index, item in enumerate(self._sorted_ocr_result):
                if index in self.usedIds:
                    continue
                re_match = re.search(self._regular_map[field_key], item.text, re.A)
                if not re_match:
                    continue
                self.usedIds.append(index)
                center_id = index
                break
            if center_id == -1:
                continue
            title2id[field_key] = center_id
        return title2id

    def parsing_medical_device_record(self):
        """医疗器械备案凭证解析　　个性化"""
        title2text = dict()
        merged_text_lst = self.mdr_regular_expression()
        supplier_name, product_name, certificate_code, issue_date = "", "", "", ""
        for text in merged_text_lst:
            if not supplier_name:
                _match = re.search(".{5,30}公司", text)
                if _match:
                    supplier_name = _match.group()
            if not product_name:
                _match = re.search(":(.{2,10})予以备案", text)
                if _match:
                    product_name = _match.group(1)
            if not certificate_code:
                _match = re.search("(.{0,3}号:|备案号)(.{1,15})", text)
                if _match:
                    certificate_code = _match.groups()[-1]
            if not issue_date:
                _match = re.search("日期:?(.{0,15})", text)
                if _match:
                    issue_date = _match.group(1)
        title2text["supplierName"] = supplier_name
        title2text["productName"] = product_name
        title2text["certificateCode"] = certificate_code
        title2text["issueDate"] = issue_date
        return title2text

    def pre_process_on_rect(self, is_plot=True):
        print("\n原始OCR数据：\n" + json.dumps([item.text for item in self._sorted_ocr_result], ensure_ascii=False) + "\n")
        if is_plot:
            self._plot_rect()
        self._special_text_rect()

        print("======步骤一：特殊矩形框检测======")
        for _id in self.usedIds:
            print(_id, self._sorted_ocr_result[_id].text, self._sorted_ocr_result[_id].newBbox)
        print("======以上矩形框不再检测======\n")

    @staticmethod
    def __is_candidate_ids(candidate_text):
        candidate_text = candidate_text.replace("：", ":").replace(";", ":").replace("；", ":")
        candidate_lst = candidate_text.split(":")

        if len(candidate_lst) >= 2 and len(candidate_lst[1]) >= 2:
            return True
        if len(candidate_text) >= 10:
            return True
        return False

    def generated_candidate_box(self, title2id):
        """生成候选框"""
        title2candidates = dict()
        print("======步骤二：【生成候选框】(通用过滤方式)======")
        for field_key, center_id in title2id.items():
            if self._line2mode[field_key] == self.MULTI:
                count = 15
            else:
                count = 5
            if self._line2mode[field_key] == self.SINGLE and\
                    self.__is_candidate_ids(self._sorted_ocr_result[center_id].text):
                candidate_ids = []
            else:
                candidate_ids = self._common_candidates_bbox(field_key, center_id, count)
            title2candidates[field_key] = candidate_ids
            print(field_key, center_id, self._sorted_ocr_result[center_id].text,
                  [self._sorted_ocr_result[a].text for a in candidate_ids])
        print("======以上为【生成候选框】(通用过滤方式)======\n")
        return title2candidates

    def exact_from_candidates_bbox(self, title2id, title2candidate):
        print("======步骤三： 过滤候选框(对候选框字段进行过滤)======")
        title2text = dict()

        for field_key, center_id in title2id.items():
            func_name = hump2under_line("filter_"+field_key.split("_")[0])
            candidate_ids = title2candidate[field_key]
            attr_name = self._line2mode[field_key]

            if hasattr(self, func_name):
                filter_text = self.__getattribute__(f"{func_name}")(field_key, center_id, candidate_ids)
            elif attr_name == self.MULTI:
                filter_text = self.common_multi_lines_filter(center_id, candidate_ids)
            elif attr_name == self.SINGLE:
                filter_text = self.common_single_line_filter(field_key, center_id, candidate_ids)
            else:
                raise ValueError(f"{field_key}没有对应的解决方案!")

            if hasattr(self.ecf, field_key):
                filter_text = self.ecf.__getattribute__(field_key)(filter_text)
            else:
                filter_text = self.ecf.common_exact(field_key, filter_text)
            title2text[field_key] = filter_text

        print(json.dumps(title2text, indent=2, ensure_ascii=False))
        print("======以上候选框为过滤后的结果======\n")
        return title2text

    def left_strip(self, normalized_val):
        for _char in self._specialChars:
            normalized_val = normalized_val.lstrip(_char)
        return normalized_val

    def parse_structure_data(self):
        self.pre_process_on_rect()

        if self._certificateName == YLQXBAZ:
            title2text = self.parsing_medical_device_record()
            self._normalize_every_field(title2text)
            return self._result

        title2id = self.get_center2id_position()
        title2candidates = self.generated_candidate_box(title2id)
        title2text = self.exact_from_candidates_bbox(title2id, title2candidates)
        self._normalize_every_field(title2text)
        return self._result
